﻿using Framework.Core.Consts;
using Microsoft.Extensions.Primitives;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Security.Claims;
using Microsoft.Extensions.Primitives;
using my.abp.Domain.Managers;
using my.abp.Domain.Shared.Entities;
using my.abp.Domain.IManagers.User;
using System.IdentityModel.Tokens.Jwt;
using Microsoft.IdentityModel.Tokens;
using System.Text;
using Framework.Core.Options;
using System.Configuration;
using Microsoft.Extensions.Options;

namespace my.abp.Domain.Authorization
{
	/// <summary>
	/// Token刷新中间件
	/// </summary>
	public class RefreshTokenMiddleware : IMiddleware, ITransientDependency
	{
		private AccountManager _accountManager;
		private Framework.AspNetCore.User.CurrentUser _CurrentUser;
		private ISysUserManager _sysUserManager;
		private readonly JwtOptions _jwtOptions;

		public RefreshTokenMiddleware(IOptions<JwtOptions> jwtOptions,AccountManager accountManager, ISysUserManager sysUserManager, 
			Framework.AspNetCore.User.CurrentUser currentUser)
		{
			_accountManager = accountManager;
			_sysUserManager = sysUserManager;
			_CurrentUser = currentUser;
			_jwtOptions = jwtOptions.Value;
		}

		/// <summary>
		/// 刷新accessToken
		/// </summary>
		/// <param name="accessToken">过期的accessToken</param>
		/// <returns></returns>
		/// <exception cref="Exception"></exception>
		public JwtSecurityToken? RefreshToken(string accessToken)
		{
			var jwtSecurityTokenHandler = new JwtSecurityTokenHandler();
			bool isCan = jwtSecurityTokenHandler.CanReadToken(accessToken);//验证Token格式
			if (!isCan)
				throw new Exception("传入访问令牌格式错误");

			var validateParameter = new TokenValidationParameters()//验证参数
			{
				ValidateAudience = true,
				// 验证发布者
				ValidateIssuer = true,
				// 验证过期时间
				ValidateLifetime = false,
				// 验证秘钥
				ValidateIssuerSigningKey = true,
				// 读配置Issure
				ValidIssuer = _jwtOptions.Issuer,
				// 读配置Audience
				ValidAudience = _jwtOptions.Audience,
				// 设置生成token的秘钥
				IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_jwtOptions.SecurityKey))
			};

			//验证传入的过期的AccessToken
			SecurityToken validatedToken;
			try
			{
				jwtSecurityTokenHandler.ValidateToken(accessToken, validateParameter, out validatedToken);//微软提供的验证方法。那个out传出的参数，类型是是个抽象类，记得转换
				return validatedToken as JwtSecurityToken;
			}
			catch (SecurityTokenException)
			{
				return null;
			}
		}

		public async Task InvokeAsync(HttpContext context, RequestDelegate next)
		{
			string accessControlExposeKey = "Access-Control-Expose-Headers";
			var refreshToken = context.Request.Headers["refresh_token"].ToString();
			if (!string.IsNullOrEmpty(refreshToken))
			{
				JwtSecurityToken? token= RefreshToken(refreshToken);

				if(token != null)
				{
					var Account = token.Claims?.FirstOrDefault(c => c.Type == ClaimConst.Account)?.Value;

					SysUser user = await _sysUserManager.GetAsync(Account);
					var access_Token = await _accountManager.GetToken(user);
					var refresh_Token = await _accountManager.GetRefreshToken(user);
					context.Response.Headers["access_token"] = access_Token;
					context.Response.Headers["refresh_token"] = refresh_Token;

					//请求头替换，补充后续鉴权逻辑
					context.Request.Headers["Authorization"] = "Bearer " + access_Token;

					// 处理 axios 问题
					context.Response.Headers.TryGetValue(accessControlExposeKey, out var acehs);
					context.Response.Headers[accessControlExposeKey] = string.Join(',', StringValues.Concat(acehs, new StringValues(new[] { "access_token", "refresh_token" })).Distinct());
				}
			}
			await next(context);
		}
	}
}
